package com.easydisk.file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easydisk.common.util.*;
import com.easydisk.constant.CommonConstant;
import com.easydisk.constant.ShareConstant;
import com.easydisk.file.feignclient.UserFeignClient;
import com.easydisk.file.mapper.ShareFileMapper;
import com.easydisk.file.mapper.ShareMapper;
import com.easydisk.file.model.entity.Share;
import com.easydisk.file.model.entity.ShareFile;
import com.easydisk.file.model.vo.UserFileVO;
import com.easydisk.file.model.vo.UserShareDetailVO;
import com.easydisk.file.model.vo.UserShareSimpleDetailVO;
import com.easydisk.file.model.vo.UserShareUrlVO;
import com.easydisk.file.service.ShareService;
import com.easydisk.file.service.UploadFileService;
import com.easydisk.file.service.UserFileService;

import com.easydisk.response.ApiResponse;
import com.easydisk.response.ResponseCode;
import com.easydisk.user.ShareUserInfoVO;
import com.google.common.collect.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户分享文件表 服务实现类
 * </p>
 *
 * @author word
 * @since 2023-09-08
 */
@Service
public class ShareServiceImpl extends ServiceImpl<ShareMapper, Share>
        implements ShareService {

    @Autowired
    private ShareMapper shareMapper;

    @Autowired
    private UserFileService userFileService;
    @Autowired
    private ShareFileMapper shareFileMapper;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private UploadFileService uploadFileService;

    public static final String DEFAULT_SHARE_PREFIX = "http://47.115.224.73/share/public/";


    @Override
    public void refreshShareStatus(List<Long> fileIds) {
        List<Share> shareList = shareMapper.selectBatchIds(fileIds);
        if (CollectionUtils.isEmpty(shareList)) {
            return;
        }
        for (Share share : shareList) {
            this.refreshShareStatus(share.getId());
        }
    }

    /**
     * 刷新一个分享的状态
     */
    private void refreshShareStatus(Long shareId) {
        ShareConstant.ShareStatus shareStatus = ShareConstant.ShareStatus.NORMAL;
        if (!checkShareFileAvailable(shareId)) {
            shareStatus = ShareConstant.ShareStatus.FILE_DELETED;
        }
        Share share = shareMapper.selectById(shareId);
        if (share == null) {
            return;
        }
        if (share.getShareStatus().equals(shareStatus.getCode())) {
            return;
        }
        UpdateWrapper<Share> query = new UpdateWrapper<>();
        query.eq("id", shareId);
        query.set("share_status", shareStatus.getCode());
        int update = shareMapper.update(null, query);

        if (update != CommonConstant.ONE_INT) {
            throw new RuntimeException("更新分享状态失败");
        }
    }
    /**
     * 校验分享文件是否有效
     *
     */
    private boolean checkShareFileAvailable(Long shareId) {
        List<ShareFile> shareList = shareFileMapper.selectList(new QueryWrapper<ShareFile>()
                                                        .eq("share_id", shareId)
                                                        .select("file_id"));
        List<Long> list = shareList.stream()
                .map(ShareFile::getFileId).collect(Collectors.toList());
        return userFileService.checkAllUpFileAvailable(list);
    }

    /**
     * 创建分享链接
     */
    @Override
    public UserShareUrlVO addShare(String shareName, Integer shareType, Integer shareDayType, String shareFileIds, Long userId) {
        Share share = addShare(shareName, shareType, shareDayType, userId);
        addShareFile(share.getId(), shareFileIds, userId);
        return assembleShareUrlVO(share);
    }

    /**
     * 保存分享信息
     *
     */
    private Share addShare(String shareName, Integer shareType, Integer shareDayType, Long userId) {
        Share share = assembleToShare(shareName, shareType, shareDayType, userId);
        int cnt = shareMapper.insert(share);
        if (cnt != CommonConstant.ONE_INT) {
            throw new RuntimeException("创建分享链接失败");
        }
        return share;
    }

    /**
     * 拼装分享主体信息
     *
     */
    private Share assembleToShare(String shareName, Integer shareType, Integer shareDayType, Long userId) {
        Share share = new Share();
        Integer shareDay = ShareConstant.ShareDayType.getDaysByCode(shareDayType);
        if (Objects.equals(CommonConstant.MINUS_ONE_INT, shareDay)) {
            throw new RuntimeException("分享天数获取失败");
        }
        Long shareId = IdGenerator.nextId();
        share.setId(shareId);
        share.setShareName(shareName);
        share.setShareType(shareType);
        share.setShareDayType(shareDayType);
        share.setShareDay(shareDay);
        share.setShareEndTime(DateUtil.afterDays(shareDay));
        share.setShareUrl(createShareUrl(shareId));
        share.setShareCode(ShareCodeUtil.get());
        share.setShareStatus(ShareConstant.ShareStatus.NORMAL.getCode());
        share.setCreateUser(userId);
        share.setCreateTime(new Date());
        return share;
    }

    /**
     * 创建分享链接
     */
    private String createShareUrl(Long shareId) {
        return DEFAULT_SHARE_PREFIX + shareId;
    }

    /**
     * 批量插入分享内容
     */
    private void addShareFile(Long shareId, String shareFileIds, Long userId) {
        List<Long> fileIdList = StringListUtil.string2LongList(shareFileIds);
        List<ShareFile> shareFileList = new ArrayList<>();
        fileIdList.forEach(fileId ->{
            ShareFile shareFile = new ShareFile();
            shareFile.setId(IdGenerator.nextId());
            shareFile.setShareId(shareId);
            shareFile.setFileId(fileId);
            shareFile.setCreateTime(new Date());
            shareFile.setCreateUser(userId);
            shareFileList.add(shareFile);
        });
        shareFileList.forEach(shareFile -> shareFileMapper.insert(shareFile));
    }

    /**
     * 拼装分享链接返回实体
     *
     */
    private UserShareUrlVO assembleShareUrlVO(Share share) {
        UserShareUrlVO rPanUserShareUrlVO = new UserShareUrlVO();
        rPanUserShareUrlVO.setShareId(share.getId());
        rPanUserShareUrlVO.setShareName(share.getShareName());
        rPanUserShareUrlVO.setShareUrl(share.getShareUrl());
        rPanUserShareUrlVO.setShareCode(share.getShareCode());
        rPanUserShareUrlVO.setShareStatus(share.getShareStatus());
        return rPanUserShareUrlVO;
    }

    /**
     * 查询分享列表
     *
     */
    @Override
    public List<UserShareUrlVO> shareList(Long userId) {
        QueryWrapper<Share> query = new QueryWrapper<>();
        query.eq("create_user", userId);
        query.orderByDesc("create_time");
        List<Share> shareList = shareMapper.selectList(query);
        List<UserShareUrlVO> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(shareList)) {
            for (Share share : shareList) {
                UserShareUrlVO userShareUrlVO = new UserShareUrlVO();
                BeanUtils.copyProperties(share, userShareUrlVO);
                userShareUrlVO.setShareId(share.getId());
                list.add(userShareUrlVO);
            }
        }
        return list;
    }


    /**
     * 取消分享链接（支持批量）
     *
     * @param shareIds  shareId 是分享表的主键
     * @param userId
     */
    @Override
    public void cancelShares(String shareIds, Long userId) {
        List<Long> shareIdList = StringListUtil.string2LongList(shareIds);
        shareMapper.deleteBatchIds(shareIdList);
        // 取消分享文件列表
        cancelShareFiles(shareIdList);
    }

    /**
     * 取消分享文件列表
     *
     * @param shareIdList
     */
    private void cancelShareFiles(List<Long> shareIdList) {
        QueryWrapper<ShareFile> query = new QueryWrapper<>();
        query.in("share_id", shareIdList);
        shareFileMapper.delete(query);
    }

    /**
     * 获取分享详情
     */
    @Override
    public UserShareDetailVO getShareDetail(Long shareId) {
        Share share = checkShareStatus(shareId);

        //拼装分享详情返回实体
        UserShareDetailVO userShareDetailVO = new UserShareDetailVO();
        userShareDetailVO.setShareId(share.getId());
        userShareDetailVO.setShareName(share.getShareName());
        userShareDetailVO.setCreateTime(share.getCreateTime());
        userShareDetailVO.setShareDay(share.getShareDay());
        userShareDetailVO.setShareEndTime(share.getShareEndTime());

        List<UserFileVO> userFileInfoList = this.getUserFileVOListByShareId(share.getId());
        userShareDetailVO.setUserFileVOList(userFileInfoList);
        // 获取分享的用户信息
        ApiResponse<ShareUserInfoVO> shareUserInfo = userFeignClient.getShareUserInfo(share.getCreateUser());
        if (shareUserInfo.getStatus() == 1) {
            throw new RuntimeException("获取分享的用户信息失败");
        }
        ShareUserInfoVO userInfoVO = shareUserInfo.getData();
        userShareDetailVO.setShareUserInfoVO(userInfoVO);
        return userShareDetailVO;
    }

    /**
     * 通过分享id，查询文件列表信息
     */
    public List<UserFileVO>  getUserFileVOListByShareId(Long shareId) {
       // 根据分享id查找文件id
        QueryWrapper<ShareFile> query = new QueryWrapper<>();
        query.eq("share_id", shareId);
        query.select("file_id");
        List<ShareFile> shareFileList = shareFileMapper.selectList(query);
        List<Long> fileIdList = shareFileList.stream().map(ShareFile::getFileId).collect(Collectors.toList());
        return userFileService.getUserFileList(fileIdList);
    }

    /**
     * 校验分享状态
     *
     */
    private Share checkShareStatus(Long shareId) {
        Share share = shareMapper.selectById(shareId);
        // 分享是否取消
        if (Objects.isNull(share)) {
            throw new RuntimeException(ResponseCode.SHARE_CANCELLED.getDesc());
        }
        // 是否分享的文件丢失
        if (Objects.equals(ShareConstant.ShareStatus.FILE_DELETED.getCode(), share.getShareStatus())) {
            throw new RuntimeException(ResponseCode.SHARE_FILE_MISS.getDesc());
        }
        // 是否永久有效
        if (Objects.equals(ShareConstant.ShareDayType.PERMANENT_VALIDITY.getCode(), share.getShareDayType())) {
            return share;
        }
        // 是否过期
        if (share.getShareEndTime().before(new Date())) {
            throw new RuntimeException(ResponseCode.SHARE_EXPIRE.getDesc());
        }
        return share;
    }

    /**
     * 获取简单分享详情
     */
    @Override
    public UserShareSimpleDetailVO getShareSimpleDetail(Long shareId) {
        Share share = checkShareStatus(shareId);
        UserShareSimpleDetailVO userShareSimpleDetailVO = new UserShareSimpleDetailVO();
        userShareSimpleDetailVO.setShareId(share.getId());
        userShareSimpleDetailVO.setShareName(share.getShareName());
        ApiResponse<ShareUserInfoVO> shareUserInfo = userFeignClient.getShareUserInfo(share.getCreateUser());
        ShareUserInfoVO shareUserInfoData = shareUserInfo.getData();
        userShareSimpleDetailVO.setShareUserInfoVO(shareUserInfoData);
        return userShareSimpleDetailVO;
    }

    /**
     * 加密用户名
     *
     * @param shareUserInfoVO
     */
    private void encryptUsername(ShareUserInfoVO shareUserInfoVO) {
        String username = shareUserInfoVO.getUsername();
        StringBuilder stringBuffer = new StringBuilder(username);
        stringBuffer.replace(CommonConstant.TWO_INT, username.length() - CommonConstant.TWO_INT,
                "****");
        shareUserInfoVO.setUsername(stringBuffer.toString());
    }

    /**
     * 校验分享码
     *
     * @param shareId
     * @param shareCode
     * @return
     */
    @Override
    public String checkShareCode(Long shareId, String shareCode) {
        Share rPanShare = checkShareStatus(shareId);
        if (!Objects.equals(rPanShare.getShareCode(), shareCode)) {
            throw new RuntimeException("分享码错误");
        }
        String token = JwtUtil.generateToken(UUIDUtil.getUUID(),
                CommonConstant.SHARE_ID, shareId, CommonConstant.ONE_HOUR_LONG);
        return token;
    }

    @Override
    public List<UserFileVO> getShareUserFileList(Long shareId, Long parentId) {
        checkShareStatus(shareId);
        List<UserFileVO> userFileVOList =
                checkFileIsOnShareStatusAndGetAllShareUserFiles(shareId, StringListUtil.longListToString(parentId));
        userFileVOList = userFileVOList.stream()
                .collect(Collectors.groupingBy(UserFileVO::getParentId)).get(parentId);
        if (CollectionUtils.isEmpty(userFileVOList)) {
            return Lists.newArrayList();
        }
        return userFileVOList;
    }

    /**
     * 校验该文件是否在分享状态并且返回该用户分享涉及的全部文件列表
     *
     * @return
     */
    private List<UserFileVO> checkFileIsOnShareStatusAndGetAllShareUserFiles(Long shareId, String fileIds) {
        List<UserFileVO> userFileVOList = this.getAllShareFileInfoList(shareId);
        if (CollectionUtils.isEmpty(userFileVOList)) {
            throw new RuntimeException("分享信息不可用");
        }
        Set<Long> shareFileIdSet = userFileVOList.stream()
                .map(UserFileVO::getFileId).collect(Collectors.toSet());
        int originSize = shareFileIdSet.size();
        shareFileIdSet.addAll(StringListUtil.string2LongList(fileIds));
        if (originSize != shareFileIdSet.size()) {
            throw new RuntimeException(ResponseCode.ERROR_PARAM.getDesc());
        }
        return userFileVOList;
    }

    /**
     * 校验该文件列表是否处于分享状态
     *
     */
    private void checkFileIsOnShareStatus(Long shareId, String fileIds) {
        checkFileIsOnShareStatusAndGetAllShareUserFiles(shareId, fileIds);
    }

    /**
     * 获取该分享的所有文件列表
     */
    private List<UserFileVO> getAllShareFileInfoList(Long shareId) {
        // 获取用户的分享id 对应的文件id
        QueryWrapper<ShareFile> query = new QueryWrapper<>();
        query.eq("share_id", shareId);
        query.select("file_id");
        List<ShareFile> shareFileList = shareFileMapper.selectList(query);
        if (CollectionUtils.isEmpty(shareFileList)) {
            throw new RuntimeException("获取用户分享文件错误");
        }
        List<Long> fileIdList = shareFileList.stream().map(ShareFile::getFileId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(fileIdList)) {
            return new ArrayList<>();
        }
        // 获取对应文件列表的所有文件以及子文件信息
        return userFileService.getAllUserFileVOList(StringListUtil.longListToString(fileIdList));
    }

    /**
     * 保存至我的网盘
     *
     */
    @Override
    public void addShareToNetDisk(Long shareId, String fileIds, Long targetParentId, Long userId) {
        checkShareStatus(shareId);
        checkFileIsOnShareStatus(shareId, fileIds);
        userFileService.copyFiles(fileIds, targetParentId, userId);
    }

    /**
     * 分享文件下载
     */
    @Override
    public void downloadShare(Long shareId, Long fileId, HttpServletResponse response) {
        checkShareStatus(shareId);
        checkFileIsOnShareStatus(shareId, StringListUtil.longListToString(fileId));
        uploadFileService.downloadFile(fileId, response);
    }
}
